#pragma once

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <functional>
#include "Fail.hpp"

static uint16_t default_port = 8080; //默认端口号

//using:给std::function<std::string(std::string)>起别名为func_t
using func_t = std::function<std::string(std::string)>;

class UdpServer
{
public:
    UdpServer(func_t task1, uint16_t port = default_port)
        : _task1(task1)
        , _port(port)
    {}

    void InitServer()
    {
        //1.创建套接字
        _sock = socket(AF_INET, SOCK_DGRAM, 0);
        if(_sock < 0)
        {
            perror("create socket fail");
            exit(SOCKET_FAIL);
        }
        std::cout << "create socket success, _sock: " << _sock << std::endl;

        //2.给服务器指明ip和port
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));

        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        //local.sin_addr.s_addr = inet_addr(_ip.c_str()); //inet_addr自动将ip从点分制转换为4字节整数,并且从主机序列转换为网络序列
        local.sin_addr.s_addr = INADDR_ANY; //云服务器不能给定ip地址, INADDR_ANY表示任意地址

        if(bind(_sock, (struct sockaddr*)&local, sizeof(local)) < 0)
        {
            perror("bind fail");
            exit(BIND_FAIL);
        }
        std::cout << "bind success, _port: " << _port << std::endl;
    }

    void Start()
    {
        while(true)
        {
            char buff[2048];

            //用于接收向服务器发消息的客户端的信息
            struct sockaddr_in sender;
            socklen_t len = sizeof(sender);
            memset(&sender, 0, sizeof(sender));

            //接收消息
            //n表示实际接收到的字节数
            int n = recvfrom(_sock, buff, sizeof(buff) - 1, 0, (struct sockaddr*)&sender, &len);
            if(n > 0)
            {
                buff[n] = '\0';
            }
            else
            {
                continue;
            }

            //提取消息并做格式化输出
            std::string sender_ip = inet_ntoa(sender.sin_addr);
            uint16_t sender_port = ntohs(sender.sin_port);
            std::cout << sender_ip << ":" << sender_port << "# " << buff << std::endl;

            std::string task1_result = _task1(buff); //处理任务1

            //自拟业务需求--将接收到的消息发送回客户端
            if(sendto(_sock, task1_result.c_str(), task1_result.size(), 0, (struct sockaddr*)&sender, sizeof(sender)) < 0)
            {
                perror("sendto fail");
                exit(SENDTO_FAIL);
            }
        }
    }

    ~UdpServer()
    {}

private: 
    int _sock; //套接字
    func_t _task1;
    uint16_t _port; //端口
    //std::string _ip; //云服务器不需要给定ip地址
};